package vip.zhenzicheng.test.juc.lock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 可重入读写锁案例
 *
 * @author zhenzicheng
 * @date 2022-09-21 10:36
 */
public class ReentrantReadWriteLockCase {

  final ReadWriteLock rwLock = new ReentrantReadWriteLock();
  Map<String, String> map = new HashMap<>();

  public void write(String key, String value) {
    rwLock.writeLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + "\t正在写入:\tkey: " + key + ",value: " + value);
      map.put(key, value);
      try {
        TimeUnit.MILLISECONDS.sleep(500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + "\t写入完毕");

    } finally {
      rwLock.writeLock().unlock();
    }
  }

  public void read(String key) {
    rwLock.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + "\t正在读取");
      String result = map.get(key);
      try {
        TimeUnit.MILLISECONDS.sleep(300);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + "\t读取完毕:\t" + result);
    } finally {
      rwLock.readLock().unlock();
    }
  }

  public static void main(String[] args) {
    ReentrantReadWriteLockCase myResource = new ReentrantReadWriteLockCase();
    for (int i = 0; i < 3; i++) {
      final int fI = i;
      new Thread(() -> myResource.write(String.valueOf(fI), String.valueOf(fI)), String.valueOf(i)).start();
    }

    for (int i = 0; i < 8; i++) {
      final int fI = i;
      new Thread(() -> myResource.read(String.valueOf(fI)), String.valueOf(i)).start();
    }

    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    // 写锁饥饿
    for (int i = 0; i < 3; i++) {
      final int fI = i;
      new Thread(() -> myResource.write(String.valueOf(fI), "xxx"), String.valueOf(i)).start();
    }
  }
}

/**
 * ReentrantReadWriteLock 锁降级案例，写锁降为读锁
 */
class LockDownCase {

  public static void main(String[] args) {
    ReadWriteLock rwLock = new ReentrantReadWriteLock();
    rwLock.writeLock().lock();
    System.out.println("----写入");
    // 写完后想马上获取读取结果
    rwLock.readLock().lock();
    System.out.println("----读取");
    // 先释放读锁，再释放写锁
    rwLock.writeLock().unlock();
    rwLock.readLock().unlock();
  }
}
